package mobile.game.core.support;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.MessageDigest;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.apache.logging.log4j.message.ParameterizedMessage;

import mobile.game.core.config.JowConfig;

/**
 * @author gaopan
 *
 * 工具类，各种乱七八糟的接口
 */
@SuppressWarnings("deprecation")
public class Utils {
	public static final String OS = System.getProperty("os.name");
	public static final String TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
	
	/**
	 * 判断是否window系统
	 * @return
	 */
	public static boolean isWin() {
		return OS.startsWith("Windows");
	}
	
	/**
	 * 判断是否linux系统
	 * @return
	 */
	public static boolean isLinux() {
		return OS.equals("Linux");
	}
	
	
	public static int bytesToInt(byte[] b, int offset) {
		int num = 0;
		for(int i = offset; i < offset + 4; ++i) {
			num <<= 8;
			num |= (b[i] & 0xff);
		}
		
		return num;
	}
	
	private static char HEX_DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
	
	/**
	 * MD5加密
	 * @param s	被加密的字符串
	 * @return	加密后的字符串
	 */
	public static String md5(String s) {
		if(s == null) {
			s = "";
		}
		
		try {
			byte[] strTemp = s.getBytes("UTF-8");
			MessageDigest mdTemp = MessageDigest.getInstance("MD5");
			mdTemp.update(strTemp);
			byte[] md = mdTemp.digest();
			char str[] = new char[md.length * 2];
			for(int i = 0; i < md.length; i++) {
				byte byte0 = md[i];
				str[i * 2] = HEX_DIGITS[byte0 >>> 4 & 0xf];
				str[i * 2 + 1] = HEX_DIGITS[byte0 & 0xf];
			}
			
			return new String(str);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 判断两个对象是否相等
	 * @param objA
	 * @param objB
	 * @return
	 */
	public static boolean isEquals(Object objA, Object objB) {
		return new EqualsBuilder().append(objA, objB).isEquals();
	}
	
	/**
	 * 参数1是否为参数2的子类或接口实现
	 * @param cls
	 * @param parentCls
	 * @return
	 */
	public static boolean isInstanceof(Class<?> cls, Class<?> parentCls) {
		return parentCls.isAssignableFrom(cls);
	}
	
	/**
	 * 数组或者多个参数转成list
	 * @param ts
	 * @return
	 */
	public static List<Integer> ofList(int[] ts) {
		List<Integer> result = new ArrayList<>();
		for(int t : ts) {
			result.add(t);
		}
		
		return result;
	}
	
	/**
	 * 数组或者多个参数转成list
	 * @param ts
	 * @return
	 */
	public static List<Long> ofList(long[] ts) {
		List<Long> result = new ArrayList<>();
		for(long t : ts) {
			result.add(t);
		}
		
		return result;
	}
	
	/**
	 * 数组或者多个参数转成list
	 * @param ts
	 * @return
	 */
	public static List<Float> ofList(float[] ts) {
		List<Float> result = new ArrayList<>();
		for(float t : ts) {
			result.add(t);
		}
		
		return result;
	}
	
	/**
	 * 数组或者多个参数转成list
	 * @param ts
	 * @return
	 */
	public static List<Double> ofList(double[] ts) {
		List<Double> result = new ArrayList<>();
		for(double t : ts) {
			result.add(t);
		}
		
		return result;
	}
	
	/**
	 * 数组或者多个参数转成list
	 * @param ts
	 * @return
	 */
	public static List<Byte> ofList(byte[] ts) {
		List<Byte> result = new ArrayList<>();
		for(byte t : ts) {
			result.add(t);
		}
		
		return result;
	}
	
	/**
	 * 数组或者多个参数转成list
	 * @param ts
	 * @return
	 */
	public static List<Character> ofList(char[] ts) {
		List<Character> result = new ArrayList<>();
		for(char t : ts) {
			result.add(t);
		}
		
		return result;
	}
	
	/**
	 * 数组或者多个参数转成list
	 * @param ts
	 * @return
	 */
	public static List<Short> ofList(short[] ts) {
		List<Short> result = new ArrayList<>();
		for(short t : ts) {
			result.add(t);
		}
		
		return result;
	}
	
	/**
	 * 数组或者多个参数转成list
	 * @param ts
	 * @return
	 */
	public static List<Boolean> ofList(boolean[] ts) {
		List<Boolean> result = new ArrayList<>();
		for(boolean t : ts) {
			result.add(t);
		}
		
		return result;
	}
	
	/**
	 * 数组或者多个参数转成list
	 * @param ts
	 * @return
	 */
	@SafeVarargs
	public static <T> List<T> ofList(T...ts) {
		return Arrays.asList(ts);
	}

	/**
	 * 构造Map对象
	 * @param <T>
	 * @param ts
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <K, V> Map<K, V> ofMap(Object...params) {
		LinkedHashMap<K, V> result = new LinkedHashMap<K, V>();
		
		// 无参 返回空即可
		if(params == null || params.length == 0) {
			return result;
		}
		
		// 处理成对参数
		int len = params.length;
		for (int i = 0; i < len; i += 2) {
			K key = (K) params[i];
			V val = (V) params[i + 1];
			
			result.put(key, val);
		}
		
		return result;
	}
	
	/**
	 * 判断数组中是否包含指定值
	 * @param arr
	 * @param value
	 * @return
	 */
	public static <T> boolean contains(T[] arr, T value) {
		for(T v : arr) {
			if(v.equals(value)) {
				return true;
			}
		}
		
		return false;
	}
	
	public static boolean contains(int[] arr, int value) {
		for(int v : arr) {
			if(v == value) {
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * 基于参数创建字符串
	 * #0开始
	 * @param str
	 * @param params
	 * @return
	 */
	public static String createStr(String str, Object...params) {
		return ParameterizedMessage.format(str, params);
	}
	
	/**
	 * 类似csharp的字符串格式化
	 * @param str
	 * @param params
	 * @return
	 */
	public static String createStrCSharp(String str, Object...params) {
		return MessageFormat.format(str, params);
	}
	
 	/**
	 * 把容器中的元素用分隔符","连接起来，返回字符串
	 * @param list
	 * @return
	 */
	public static <T> String join(Collection<T> list) {
		if(list == null) {
			return "";
		}
		
		return String.join(",", list.stream().map(String::valueOf).collect(Collectors.toList()));
	}
    
	/**
	 * 读取配置文件
	 * @param name
	 * @return
	 */
	public static Properties readProperties(String name) {
		String filePath = Thread.currentThread().getContextClassLoader().getResource(name).getPath();
		try(FileInputStream in = new FileInputStream(filePath)) {
			Properties p = new Properties();
			p.load(in);
			
			return p;
		} catch (Exception e) {
			throw new SysException(e);
		}
	}
	
	//--------------------------------------------------------------------------------
	// 反射相关的，因为性能问题，谨慎使用
	
	/**
	 * 全反射，不建议使用
	 * 获取对象的属性 
	 * 会先尝试利用getter方法获取 然后再直接访问字段属性
	 * 如果给定的属性不存在 会返回null
	 * @param obj
	 * @param fieldName
	 * @return
	 */
	@Deprecated
	@SuppressWarnings("unchecked")
	public static <T> T fieldRead(Object obj, String fieldName) {
		try {
			Class<? extends Object> clazz = obj.getClass();
			
			// 先通过自省来获取字段的值(getter方法)
			BeanInfo bi = Introspector.getBeanInfo(clazz);
			PropertyDescriptor[] pds = bi.getPropertyDescriptors();
			for(PropertyDescriptor p : pds) {
				if(!p.getName().equals(fieldName)) {
					continue;
				}
				
				return (T)p.getReadMethod().invoke(obj);
			}
			
			// 如果通过getter方法没找到 那么就尝试直接读取字段
			Field f = clazz.getField(fieldName);
			return (T)f.get(obj);
		} catch (Exception e) {
			throw new SysException(e);
		}
	}
	
	/**
	 * 获取对象的静态属性
	 * @param clazz
	 * @param fieldName
	 * @return
	 */
	@Deprecated
	@SuppressWarnings("unchecked")
	public static <T> T fieldRead(Class<?> clazz, String fieldName) {
		try {
			Field field = FieldUtils.getDeclaredField(clazz, fieldName);
			return (T) field.get(clazz);
		} catch (Exception e) {
			throw new SysException(e);
		}
	}
	
	/**
	 * 设置对象的属性  不建议使用
	 * 会先尝试利用setter方法修改 然后再直接修改字段属性
	 * 如果给定的属性不存在 会抛出异常
	 * @param obj
	 * @param fieldName
	 * @return
	 */
	@Deprecated
	public static void fieldWrite(Object obj, String fieldName, Object valueNew) {
		try {
			Class<? extends Object> clazz = obj.getClass();
			
			// 先通过自省来设置字段的值(setter方法)
			BeanInfo bi = Introspector.getBeanInfo(clazz);
			PropertyDescriptor[] pds = bi.getPropertyDescriptors();
			for(PropertyDescriptor p : pds) {
				if(!p.getName().equals(fieldName)) {
					continue;
				}
				
				// 到这里的话 证明属性能找到（至少有对应的getter）但是没有找到setter
				// 可能是setter方法不符合规范 比如非void有返回值等
				// 这种情况使用反射再次尝试
				Method wm = p.getWriteMethod();
				if(wm == null) {
					String wmStr = "set" + StringUtils.capitalize(fieldName);
					for(Method m : clazz.getMethods()) {
						if(!m.getName().equals(wmStr)) {
							continue;
						}
						
						m.invoke(obj, valueNew);
						return;
					}
				} else {
					wm.invoke(obj, valueNew);
					return;
				}
			}
			
			// 如果通过setter方法没找到 那么就尝试直接操作字段
			Field f = clazz.getField(fieldName);
			f.set(obj, valueNew);
		} catch (Exception e) {
			throw new SysException(e);
		}
	}
	
	/**
	 * 通过反射执行函数
	 * @param obj
	 * @param method
	 * @param param
	 */
	@SuppressWarnings("unchecked")
	public static <T> T invokeMethod(Object obj, String method, Object...params) {
		try {
			return (T)MethodUtils.invokeMethod(obj, method, params);
		} catch (Exception e) {
			throw new SysException(e);
		}
	}
	
	/**
	 * 通过反射执行函数
	 * @param obj
	 * @param method
	 * @param param
	 */
	@SuppressWarnings("unchecked")
	public static <T> T invokeStaticMethod(Class<?> cls, String method, Object...params) {
		try {
			return (T)MethodUtils.invokeStaticMethod(cls, method, params);
		} catch (Exception e) {
			throw new SysException(e);
		}
	}
	
	/**
	 * 通过反射执行构造函数
	 * @param cls
	 * @param params
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T invokeConstructor(Class<?> cls, Object...params) {
		try {
			return (T) ConstructorUtils.invokeConstructor(cls, params);
		} catch (Exception e) {
			throw new SysException(e);
		}
	}
	
	/**
	 * 创建函数特征码
	 * 类全路径:函数名(参数类型)
	 * @return
	 */
	public static String createMethodKey(Method method) {
		return createMethodKey(method.getDeclaringClass(), method);
	}
	
	/**
	 * 创建函数特征码
	 * 类全路径:函数名(参数类型)
	 * @return
	 */
	public static String createMethodKey(Class<?> cls, Method method) {
		// 类全路径
		String clazzName = cls.getName();
		// 函数名
		String methodName = method.getName();
		// 参数类型字符串
		StringBuilder methodParam = new StringBuilder();
		methodParam.append("(");
		for(Class<?> clazz : method.getParameterTypes()) {
			if(methodParam.length() > 1) {
				methodParam.append(", "); 
			}
			
			methodParam.append(clazz.getSimpleName());
		}
		
		methodParam.append(")");
		
		return clazzName + ":" + methodName + methodParam.toString();
	}

	/**
	 * 字符串中是否包含表情
	 * @param str
	 * @return
	 */
	public static boolean isEmo(String str) {
		String reg = "[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]";
		Pattern pattern = Pattern.compile(reg);
        Matcher matcher = pattern.matcher(str);
        while(matcher.find ()) {
        	return true;
        }
        
        return false;
	}
	
	/**
	 * 获取rpc调用处的函数信息，文件名:行号 调用者函数名
	 * @return
	 */
	public static String getCallerInfo() {
		if(!JowConfig.DEBUG_IS_OPENCALLINFO) {
			return "";
		}
		
		StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
		StackTraceElement e = stackTrace[3];
		return new StringBuilder().append(e.getFileName()).append(":")
				.append(e.getLineNumber()).append(" ")
				.append(e.getMethodName()).toString();
	}

	/**
	 * 将HUMAN_LOGIN的字符串转换为类名称标志格式：HumanLogin
	 * 
	 * @param str
	 * @return
	 */
	public static String toClassName(String str) {
		String[] ss = str.toLowerCase().split("_");
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < ss.length; i++) {
			sb.append(StringUtils.capitalize(ss[i]));
		}
		
		return sb.toString();
	}
	
	/**
	 * 将HumanLogin的字符串转换为常量名称标志格式：HUMAN_LOGIN
	 * @param str
	 * @return
	 */
	public static String toConstName(String str) {
		String[] ss = StringUtils.splitByCharacterTypeCamelCase(str);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < ss.length; ++i) {
			sb.append(StringUtils.upperCase(ss[i])).append("_");
		}
		
		sb.deleteCharAt(sb.length() - 1);
		return sb.toString();
	}
	
	/**
	 * 两个int合并为一个long
	 * @param i1
	 * @param i2
	 * @return
	 */
	public static long makeId(int i1, int i2) {
		return (long) i1 << 32 | i2;
	}
	
	/**
	 * 將字符串压缩为 gzip流
	 * @param data
	 * @return
	 */
	public static byte[] gzip(String data) {
		byte[] zipData = null;
		try(ByteArrayOutputStream baos = new ByteArrayOutputStream();
				GZIPOutputStream out = new GZIPOutputStream(baos)) {
			out.write(data.getBytes("utf-8"));
			out.finish();
			zipData = baos.toByteArray();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return zipData;
	}
	
	/**
	 * 解压gzip流
	 * @param zipData
	 * @return
	 */
	public static String gunzip(byte[] zipData) {
		String data = null;
		try(GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(zipData));
				ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
			byte[] buf = new byte[1024];
			int num = -1;
			while ((num = in.read(buf, 0, buf.length)) != -1) {
				baos.write(buf, 0, num);
			}
			
			return new String(baos.toByteArray(), "utf-8");
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return data;
	}
	
	/**
	 * 格式化字节流大小显示<BR/>
	 * 大于5MB 单位显示MB<BR/>
	 * 大于5KB 单位显示KB<BR/>
	 * 其余直接显示字节B
	 * @return 
	 */
	public static String formatByteSize(long byteSize) {
		return byteSize > 5 * SIZE_MB ? (byteSize / SIZE_MB + "MB") : (byteSize > 5 * SIZE_KB ? (byteSize / SIZE_KB + "KB") : (byteSize + "B"));
	}
	
	private static final long SIZE_KB = 1024;
	private static final long SIZE_MB = 1024 * 1024;
	
	/**
	 * 哈希分布增强
	 * 防止质量较差的哈希函数造成的影响
	 * @param hash
	 * @return
	 */
	public static int hash(int hash) {
		hash ^= (hash >>> 20) ^ (hash >>> 12);
		return hash ^ (hash >>> 7) ^ (hash >>> 4);
	}
	
	//--------------------------------------------------------------------------------
	// convert，各种类型间相互转换
	
	/**
	 * String -> int
	 * 如果出错 则为0
	 * @param value
	 * @return
	 */
	public static int intValue(String value) {
		if(StringUtils.isNotEmpty(value) && NumberUtils.isNumber(value)) {
			return Double.valueOf(value).intValue();
		} else {
			return 0;
		}
	}
	
	/**
	 * String -> long
	 * 如果出错 则为0
	 * @param value
	 * @return
	 */
	public static long longValue(String value) {
		if(StringUtils.isNotEmpty(value) && NumberUtils.isNumber(value)) {
			return Long.parseLong(value);
		} else {
			return 0L;
		}
	}
	
	/**
	 * String -> float
	 * 如果出错 则为0.0
	 * @param value
	 * @return
	 */
	public static float floatValue(String value) {
		if(StringUtils.isNotEmpty(value) && NumberUtils.isNumber(value)) {
			return Float.valueOf(value);
		} else {
			return 0.0f;
		}
	}
	
	/**
	 * String -> double
	 * 如果出错 则为0.0
	 * @param value
	 * @return
	 */
	public static double doubleValue(String value) {
		if(StringUtils.isNotEmpty(value) && NumberUtils.isNumber(value)) {
			return Double.valueOf(value);
		} else {
			return 0.0D;
		}
	}

	/**
	 * String -> boolean
	 * 如果出错 则为false
	 * @param value
	 * @return
	 */
	public static boolean booleanValue(String value) {
		if("true".equalsIgnoreCase(value) && value != null) {
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * str -> int[]</br>
	 * eg: "1,2" -> [1, 2]
	 * @param value
	 * @return
	 */
	public static int[] parseIntArray(String value) {
		if(StringUtils.isBlank(value)){
			return new int[0];
		}
		
		String[] elems = value.split(",");
		int[] result = new int[elems.length] ;
		for(int i = 0; i < elems.length; i++) {
			result[i] = Utils.intValue(elems[i]);
		}
		
		return result;
	}
	
	/**
	 * str -> long[]</br>
	 * eg: "1,2" -> [1, 2]
	 * @param value
	 * @return
	 */
	public static long[] parseLongArray(String value) {
		if(StringUtils.isBlank(value)){
			return new long[0];
		}
		
		String[] elems = value.split(",");
		long[] result = new long[elems.length] ;
		for(int i = 0; i < elems.length; i++) {
			result[i] = Utils.longValue(elems[i]);
		}
		
		return result;
	}
	
	/**
	 * str -> float[]</br>
	 * eg: "1.0,2.0" -> [1.0, 2.0]
	 * @param value
	 * @return
	 */
	public static float[] parseFloatArray(String value) {
		if(StringUtils.isBlank(value)){
			return new float[0];
		}
		
		String[] elems = value.split(",");
		float[] result = new float[elems.length] ;
		for(int i = 0; i < elems.length; i++) {
			result[i] = Utils.floatValue(elems[i]);
		}
		
		return result;
	}
	
	/**
	 * str -> double[]</br>
	 * eg: "1.0,2.0" -> [1.0, 2.0]
	 * @param value
	 * @return
	 */
	public static double[] parseDoubleArray(String value) {
		if(StringUtils.isBlank(value)){
			return new double[0];
		}
		
		String[] elems = value.split(",");
		double[] result = new double[elems.length] ;
		for(int i = 0; i < elems.length; i++) {
			result[i] = Utils.doubleValue(elems[i]);
		}
		
		return result;
  	}

	/**
	 * str -> str[]</br>
	 * eg: "1,2" -> ["1", "2"]
	 * @param value
	 * @return
	 */
	public static String[] parseStringArray(String value) {
		if(StringUtils.isBlank(value)){
			return new String[0];
		}
		
		return value.split(",");
	}
	
 	/**
 	 * str -> boolean[]</br>
	 * eg: "true,false" -> [true, false]
 	 * @param value
 	 * @return
 	 */
 	public static boolean[] parseBoolArray(String value) {
 		if(StringUtils.isBlank(value)){
			return new boolean[0];
		}
		
		String[] elems = value.split(",");
		boolean[] result = new boolean[elems.length] ;
		for(int i = 0; i < elems.length; i++) {
			result[i] = Utils.booleanValue(elems[i]);
		}
		
		return result;
 	}
 	
 	/**
	 * str -> int list</br>
	 * eg: "1,2" -> {1, 2}
	 * @param value
	 * @return
	 */
	public static List<Integer> parseIntList(String value) {
		List<Integer> result = new ArrayList<>();
		if(StringUtils.isBlank(value)){
			return result;
		}
		
		String[] elems = value.split(",");
		for(int i = 0; i < elems.length; i++) {
			result.add(Utils.intValue(elems[i]));
		}
		
		return result;
	}
 	
 	/**
	 * bytes -> int（大端格式）
	 * @param b
	 * @param offset
	 * @return
	 */
	public static int bytesToBigEndian32(byte[] b, int offset) {
		return 	(((int)b[offset+0] & 0xff) << 24) |
				(((int)b[offset+1] & 0xff) << 16) |
				(((int)b[offset+2] & 0xff) <<  8) |
				(((int)b[offset+3] & 0xff)      );
	}
	
	/**
	 * int -> bytes（大端格式）
	 * @param b
	 * @param offset
	 * @param v
	 */
	public static void bigEndian32ToBytes(byte[] b, int offset, int value) {
		b[offset+0] = (byte)((value >> 24) & 0xFF);
		b[offset+1] = (byte)((value >> 16) & 0xFF);
		b[offset+2] = (byte)((value >>  8) & 0xFF);
		b[offset+3] = (byte)((value      ) & 0xFF);
	}
	
	/**
	 * bytes -> int（小端格式）
	 * @param b
	 * @param offset
	 * @return
	 */
	public static int bytesToLittleEndian32(byte[] b, int offset) {
		return  (((int)b[offset+0] & 0xff)      ) |
				(((int)b[offset+1] & 0xff) <<  8) |
				(((int)b[offset+2] & 0xff) << 16) |
				(((int)b[offset+3] & 0xff) << 24);
	}
	
	/**
	 * int -> bytes（小端格式）
	 * @param b
	 * @param offset
	 * @param value
	 */
	public static void littleEndian32ToBytes(byte[] b, int offset, int value) {
		b[offset+0] = (byte)((value      ) & 0xFF);
		b[offset+1] = (byte)((value >>  8) & 0xFF);
		b[offset+2] = (byte)((value >> 16) & 0xFF);
		b[offset+3] = (byte)((value >> 24) & 0xFF);
	}
	
	/**
	 * 只保留几位小数
	 * @param x
	 * @param saveBitNum
	 * @return
	 */
	public static double saveDoubleBitNum(double x, int saveBitNum) {
		NumberFormat ddf1= NumberFormat.getNumberInstance() ;
		ddf1.setMaximumFractionDigits(saveBitNum);
		// 去除千分位逗号
		ddf1.setGroupingUsed(false);
		String s = ddf1.format(x) ; 
		return Utils.doubleValue(s);
	}
	
	/**
	 * 只保留几位小数
	 * @param x
	 * @param saveBitNum
	 * @return
	 */
	public static float saveDoubleBitNum(float x, int saveBitNum) {
		NumberFormat ddf1= NumberFormat.getNumberInstance() ;
		ddf1.setMaximumFractionDigits(saveBitNum);
		// 去除千分位逗号
		ddf1.setGroupingUsed(false);
		String s = ddf1.format(x) ; 
		return Utils.floatValue(s);
	}

	/********************************************************************************
	 * 新增加代码
	 * @Author : hz
	 * @version : 2017-3-15 11:43:42
	 */

	/**
	 * 从文件读取字符串
	 * @param fileName 文件名称，自动搜索classpath
	 * @param encoding 文件编码，例如:"UTF-8"
	 * @return
	 * @throws IOException 
	 */
	public static String readFileToString(String fileName, String encoding) throws IOException {
		InputStream inputStream = Thread.currentThread().getContextClassLoader()
				.getResourceAsStream(fileName);

		int size = inputStream.available();

		byte[] buffer = new byte[size];
		inputStream.read(buffer);
		inputStream.close();

		String fileString = new String(buffer, encoding);
		return fileString;
	}
}
